package parser;

import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import parser.simbolo.delimitador.*;
import parser.simbolo.operador.Operador;

public class ParserConsulta {

		
	/**
	 * Reemplaza los espacios en blanco redundantes por uno solo, 
	 * luego devuelve la cadena de caracteres resultante
	 * 
	 * @param String cadena
	 * 
	 * @return String
	 */
	public static String limpiaEspaciosVacios(String cadena){
		 while(cadena.indexOf("  ")!=-1)cadena=cadena.replaceAll("  "," ");
		 
		 return cadena;
	}
	
	/**
	 * Cuenta que la cantidad de "(" sea igual a la cantidad de ")" sino arroja una 
	 * excepcion de error de sintaxis
	 * 
	 * @param String cadena
	 * 
	 * @throws FunctionSyntacticException
	 */
	public static void parentesisPares(String cadena) throws FunctionSyntacticException{
		//Creamos los parentesis
		Delimitador parentesisAbrir = new Parentesis1();
		Delimitador parentesisCerrar = new Parentesis2();
		//Inicializamos las variables de conteo
		int cuentaParentesisIzq=0;
		int cuentaParentesisDer=0;
		//Por cada posicion de la cadena...
		for (int i=0;i<cadena.length();i++){
			//Si la posicion es igual a algun parentesis, incremento
	    	if (cadena.charAt(i) == parentesisAbrir.getAbreviado()){
	    		cuentaParentesisIzq++;
	    	}else if (cadena.charAt(i) == parentesisCerrar.getAbreviado()){
	    		cuentaParentesisDer++;
	    	}
	    }
		
		//Si la cantidad de parentesis abiertos es diferente a la cantidad de 
		// parentesis cerrados, lanzo una excepcion
		if(cuentaParentesisDer!=cuentaParentesisIzq){
			throw new FunctionSyntacticException("La cantidad de parentesis abiertos y cerrados no concuerda");
		}
		
	}
	
	/**@param : cadena String Cadena a verificar. 
	 * @throws FunctionSyntacticException
	 * Arroja Exception si se da el caso "()" o ")("
	 * */
	public static void parentesisConsecutivos(String cadena)throws FunctionSyntacticException{
		Delimitador parentesisAbrir = new Parentesis1();
		Delimitador parentesisCerrar = new Parentesis2();
		while(cadena.indexOf(" ")!=-1)cadena = cadena.replaceAll(" ", "");
		
		for (int i=0;i<cadena.length();i++){
	    	
			
			if (cadena.charAt(i)==parentesisAbrir.getSimbolo().charAt(0)&&
	    		((i+1)<cadena.length() && cadena.charAt(i+1)==parentesisCerrar.getSimbolo().charAt(0)||
	    		( i>=1&&cadena.charAt(i-1)==parentesisCerrar.getSimbolo().charAt(0)))){
	    			throw new FunctionSyntacticException("Verifique de corregir () o )(");
	    			
	    		
	    	}
		}
	}
	
	
	
	public static String espaciar(String cadena, List<Delimitador> delimitadores){	
		
		Iterator<Delimitador> del = delimitadores.iterator();
		while(del.hasNext()){			
			Delimitador d = del.next();
			cadena = cadena.replace(d.getSimbolo(), " "+d.getSimbolo()+" ");
			
		}
		cadena=limpiaEspaciosVacios(cadena); //saca espacios redundantes
		return cadena;
	}
	
	public static void operadoresVecinos(String cadena, List<Operador> operadores){
		Delimitador parentesisAbrir = new Parentesis1();
		Delimitador parentesisCerrar = new Parentesis2();
		Iterator<Operador> ops= operadores.iterator();
		String aCadena[]= cadena.split(" ");

		while(ops.hasNext()){
			Operador op = ops.next();
			//Por cada operador recorro toda la cadena			
			for(int i=0; i<aCadena.length;i++){
				if(aCadena[i].equals(op.getSimbolo())){		
									
					//Chequeo que los operadores tengan algo a la izquierda y a la derecha, exepto el NOT
					if(op.isNot()){
						if((i<(aCadena.length-1) &&  aCadena[i+1].equals(""))||(i==aCadena.length-1) )
							throw new FunctionSyntacticException("El "+op.getSimbolo()+" necesita un argumento");
						if( (i>0 && !aCadena[i-1].equals(parentesisAbrir.getSimbolo())) )
							throw new FunctionSyntacticException("El "+op.getSimbolo()+" debe ser precedido de "+parentesisAbrir.getSimbolo() );
								
					}else{
						if((i==0)||(i==(aCadena.length-1))||(i<(aCadena.length-1) &&  aCadena[i+1].equals("") && i>0 &&  aCadena[i-1].equals("")))
							throw new FunctionSyntacticException("El "+op.getSimbolo()+" necesita 2 argumentos");
						if( (i>0 && aCadena[i-1].equals(parentesisAbrir.getSimbolo())) )
							throw new FunctionSyntacticException("El "+op.getSimbolo()+" no puede ser precedido de "+parentesisAbrir.getSimbolo() );
						if( (i<(aCadena.length-1) && aCadena[i+1].equals(parentesisCerrar.getSimbolo())) )
							throw new FunctionSyntacticException("El "+op.getSimbolo()+" no puede estar seguido de "+parentesisCerrar.getSimbolo() );
						
					}
					
					
				}
				
				
			}
		}
	}
	public static void delimitadoresVecinos(String cadena, List<Operador> operadores){
		Delimitador parentesisAbrir = new Parentesis1();
		Delimitador parentesisCerrar = new Parentesis2();
		Iterator<Operador> ops;
		String aCadena[]= cadena.trim().split(" ");
		for(int i=0; i<aCadena.length;i++){
			//Verifico que antes de un parentesis abierto tenga un operador, o sea el primer caracter
			if(aCadena[i].equals(parentesisAbrir.getSimbolo()) && i>0){
				ops= operadores.iterator();
				boolean valido = false;
				while(ops.hasNext()){
					Operador op = ops.next();
					if(aCadena[i-1].equals(op.getSimbolo()) || aCadena[i-1].equals(parentesisAbrir.getSimbolo())){
						valido=true;
						break;
					}
				}
				if(!valido)throw new FunctionSyntacticException("El "+parentesisAbrir.getSimbolo()+" debe ser precedido de un operador u otro "+parentesisAbrir.getSimbolo());
			}
			if(aCadena[i].equals(parentesisCerrar.getSimbolo()) && i<(aCadena.length-1)){
				ops= operadores.iterator();
				boolean valido = false;
				while(ops.hasNext()){
					Operador op = ops.next();
					
					if(aCadena[i+1].equals(op.getSimbolo()) || aCadena[i+1].equals(parentesisCerrar.getSimbolo()) ){
						valido = true;
						break;
					}
				}
				if(!valido)throw new FunctionSyntacticException("El "+parentesisCerrar.getSimbolo()+" debe estar seguido de un operador u otro "+parentesisCerrar.getSimbolo());
				
			}
			
			
		}
		
		
		
	}
	public static void operadoresConsecutivos(String cadena, List<Operador> operadores){
		Iterator<Operador> ops= operadores.iterator();
		//reemplazo indiscrimidamente or por OR, and por AND, etc, no importa si esta en un termino
		//cadena = cadena.replaceAll(op.getSimbolo().toLowerCase(), op.getSimbolo());
		String aCadena[]= cadena.split(" ");

		while(ops.hasNext()){
			Operador op = ops.next();
			//Por cada operador recorro toda la cadena 
			for(int i=0; i<aCadena.length;i++){
				if(aCadena[i].equals(op.getSimbolo())){		
					Iterator<Operador> ops2= operadores.iterator();
					//Chequeo que el anterior y el siguiente no sea otro operador
					while(ops2.hasNext()){
						Operador op2 = ops2.next();
						if((i>0 && aCadena[i-1].equals(op2.getSimbolo()))||(i<(aCadena.length-1) &&  aCadena[i+1].equals(op2.getSimbolo()) ))
							throw new FunctionSyntacticException("No puede usar 2 operadores consecutivos"); 
					}					
					
					
				}
				
				
			}
			
			
			//Pattern p = Pattern.compile(""); // Compiles regular expression into Pattern.
		    //Matcher m = p.matcher(""); // Creates Matcher with subject s and Pattern p
			
		}
		
		
	}
	
	public static void validarConsulta(String consulta, List<Operador> operadores, List<Delimitador> delimitadores){
		consulta = espaciar(consulta,delimitadores);// Deja espacios antes y despues de los delimitadores
		 operadoresConsecutivos(consulta,operadores);
		 operadoresVecinos(consulta,operadores);
		 parentesisPares(consulta);
		 parentesisConsecutivos(consulta);
		 delimitadoresVecinos(consulta,operadores);
	}
	
	

}
